﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Athena.Core;
using Athena.Objects;

namespace Athena.IO
{
    public class XMLWriter : IModelWriter
    {
        public override void WriteModel(System.IO.Stream oStream, Model oModel)
        {
            WriteModel(oStream, oModel, false);
        }

        public static void WriteModel(System.IO.Stream oStream, Model oModel, bool encloseAsModule)
        {
            XmlTextWriter writer = new XmlTextWriter(oStream, null);
            writer.WriteStartDocument();
            writer.WriteStartElement("Model");
            IO.XMLWriter.WriteItem(oModel.BackEndModel, null, writer);
            WriteNullItems(writer, oModel.Drawables);
            writer.WriteEndElement(); //model
            writer.WriteEndDocument();
            writer.Close();
        }

        public static bool WriteItem(Item item, Item parent, XmlWriter writer)
        {
            if (writer == null || item == null) return false;

            if (item is Edge)
                writer.WriteStartElement("Edge", "");
            else
                if (item is Promoter)
                    writer.WriteStartElement("Promoter", "");
                else
                    if (item is Terminator)
                        writer.WriteStartElement("Terminator", "");
                    else
                        if (item is Gene)
                            writer.WriteStartElement("Gene", "");
                        else
                            if (item is Part)
                                writer.WriteStartElement("Part", "");
                            else
                                if (item is GlobalSpecies)
                                    writer.WriteStartElement("GlobalSpecies", "");
                                else
                                    if (item is Species)
                                        writer.WriteStartElement("Species", "");
                                    else
                                        if (item is Compartment)
                                            writer.WriteStartElement("Compartment", "");
                                        else
                                            if (item is Module)
                                                writer.WriteStartElement("Module", "");
                                            else
                                                return false;

            if (parent == null || item.Parent == null || item.Parent == parent)
            {
                item.WriteXML(writer);
                if (item.Drawable != null)
                {
                    writer.WriteStartElement("Drawable", "");
                    if (parent != null)
                        WriteDrawable(item.Drawable, parent.Drawable, writer);
                    else
                        WriteDrawable(item.Drawable, null, writer);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
            return true;
        }

        public static bool WriteDrawable(IDrawable drawable, IDrawable parent, XmlWriter writer)
        {
            if (writer == null || drawable == null) return false;

            if (drawable is ModuleConnector)
                writer.WriteStartElement("ModuleConnector", "");
            else
                if (drawable is BezierConnector)
                    writer.WriteStartElement("BezierConnector", "");
                else
                    if (drawable is PromoterGlyph)
                        writer.WriteStartElement("PromoterGlyph", "");
                    else
                        if (drawable is GeneGlyph)
                            writer.WriteStartElement("GeneGlyph", "");
                        else
                            if (drawable is TerminatorGlyph)
                                writer.WriteStartElement("TerminatorGlyph", "");
                            else
                                if (drawable is RbsGlyph)
                                    writer.WriteStartElement("RBSGlyph", "");
                                else
                                    if (drawable is PartGlyph)
                                        writer.WriteStartElement("PartGlyph", "");
                                    else
                                        if (drawable is EmptyGlyph)
                                            writer.WriteStartElement("EmptyGlyph", "");
                                        else
                                            if (drawable is SpeciesGlyph)
                                                writer.WriteStartElement("SpeciesGlyph", "");
                                            else
                                                if (drawable is MultimericSpecies)
                                                    writer.WriteStartElement("MultimericSpecies", "");
                                                else
                                                    if (drawable is CompartmentGlyph)
                                                        writer.WriteStartElement("CompartmentGlyph", "");
                                                    else
                                                        if (drawable is ModuleGlyph)
                                                            writer.WriteStartElement("ModuleGlyph", "");
                                                        else
                                                            if (drawable is Decorator)
                                                                writer.WriteStartElement("Decorator", "");
                                                            else
                                                                if (drawable is TextGlyph)
                                                                    writer.WriteStartElement("Text", "");
                                                                else
                                                                    return false;

            if (parent == null || drawable.Parent == null || drawable.Parent == parent)
            {
                drawable.WriteXML(writer);

                if (drawable.Alias != null && drawable.Alias.Count > 0)
                {
                    bool first = true;
                    foreach (IDrawable id in drawable.Alias)
                    {
                        if (id.Parent == parent)
                        {
                            if (first)
                            {
                                writer.WriteStartElement("Aliases");
                                first = false;
                            }
                            IO.XMLWriter.WriteDrawable(id, parent, writer);
                        }
                    }
                    if (!first)
                        writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
            return true;
        }

        public static void WriteNullItems(XmlWriter writer, List<IDrawable> Drawables)
        {
            if (Drawables.Count > 0)
            {
                bool first = true;

                foreach (IDrawable id in Drawables)
                {
                    if (id.NullItem && id.Original == null && id.Parent == null)
                    {
                        if (first)
                        {
                            writer.WriteStartElement("NullItems", "");
                            first = false;
                        }
                        IO.XMLWriter.WriteDrawable(id, null, writer);
                    }
                }

                if (!first)
                    writer.WriteEndElement();
            }
        }
    }
}
